#ifndef ENTERACPU_CU
#define ENTERACPU_CU

#include "enteraCPU.cuh"
#include "../utils/global.cuh"
#include "../fitness/fitnessEntera.cu"

/******************* Implementacion de Funciones del  *****************/


 void inicializarPoblacionEnteraCPU(int* poblacion, float* fitnessActual, MersenneTwister *mt, int cantCromosomasPoblacion, float* fitnessOrdenadoHostCPU, unsigned long * numerosAleatoriosInicializacion/*, int* mejorIndividuoCPU, float* mejorFitnessIndividuoCPU*/){
	//Obtengo posicion a escribir.
	int posicionCromosoma = 0;
	int posicionFitness = 0;

	for(int i = 0; i<cantGenesEnCromosoma * cantidadPoblacionesCPU * cantCromosomasPoblacion; i++){
		//Genero valor aleatorio.
		int r = obtenerNumeroEnRangoEnteraCPU(numerosAleatoriosInicializacion[posicionCromosoma+i]);
		poblacion[posicionCromosoma+i] = r;
	}

	for(int i = 0; i< cantidadPoblacionesCPU * cantCromosomasPoblacion; i++){
		fitnessActual[posicionFitness] = calcularFitnessEnteraCPU(poblacion, posicionCromosoma);
		fitnessOrdenadoHostCPU[posicionFitness] = fitnessActual[posicionFitness];
		posicionFitness++;
		posicionCromosoma = posicionCromosoma + cantGenesEnCromosoma;
	}
}

 void mainKernelEnteraCPU(int* poblacionActual, int* nuevaPoblacion, float* fitnessActual, float* nuevoFitness, int * poblacionActualAcambiar, int *  nuevaPoblacionAcambiar, int* individuosAMigrar, MersenneTwister *mt, int nroPoblacion, int posActual, int *individuoAMigrarCPUaGPUhost,  float* fitnessOrdenado, int* vectorIndicesFitnessOrdenado, int iteracion, float* probabilidadRuleta, float* fitnessTotalParaRuleta, unsigned long* numerosAleatoriosSeleccion, unsigned long* numerosAleatoriosCruzamiento, unsigned long* numerosAleatoriosMutacion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosProbabilidadMutacion, int* mejorIndividuo, float* mejorFitnessIndividuoCPU){
	 if(tipoSeleccion == 2){
		asignarProbabilidadRuletaEnteraCPU(fitnessActual, probabilidadRuleta, fitnessTotalParaRuleta, mt, nroPoblacion, posActual);
		/*printf("total = %f\n", fitnessTotalParaRuleta[0]);
		for(int i=0;i<cantCromosomasPoblacion*cantidadPoblacionesCPU;i++){
			printf("** probabilidadRuleta ** i = %d prob = %f \n",i, probabilidadRuleta[i]);
		}*/
	}
	int posicionCromosoma1 = seleccionEnteraCPU(fitnessActual, mt, tipoSeleccion, nroPoblacion, posActual, probabilidadRuleta, vectorIndicesFitnessOrdenado, numerosAleatoriosSeleccion, 0);
	int posicionCromosoma2 = seleccionEnteraCPU(fitnessActual, mt, tipoSeleccion, nroPoblacion, posActual, probabilidadRuleta, vectorIndicesFitnessOrdenado, numerosAleatoriosSeleccion, 1);
	//printf("posicionCromosoma1 = %d, posicionCromosoma2 = %d\n", posicionCromosoma1, posicionCromosoma2);
	cruzamientoRepresentacionEnteraCPU(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidadCruzamiento, mt, tipoCruzamiento, nroPoblacion, posActual, numerosAleatoriosProbabilidadCruzamiento, numerosAleatoriosCruzamiento);
	mutacionEnteraCPU(nuevaPoblacion, probabilidadMutacion, mt, tipoMutacion, nroPoblacion, posActual, numerosAleatoriosProbabilidadMutacion, numerosAleatoriosMutacion);

	asignarFitnessEnteraCPU(nuevaPoblacion, nuevoFitness, nroPoblacion, posActual,fitnessOrdenado);
	reemplazoEnteraCPU(poblacionActual, nuevaPoblacion, poblacionActualAcambiar, nuevaPoblacionAcambiar, fitnessActual, nuevoFitness, tipoReemplazo, nroPoblacion, posActual);

	if(posActual == cantCromosomasPoblacion/2 -1){
		if((generacionesMigrar > 0) && ((iteracion + 1) % generacionesMigrar == 0)){
			//si posActual(numero hilo) es el ultimo del bloque
			individuosAMigrarRepresentacionEnteraCPU(nuevoFitness, nuevaPoblacion, individuosAMigrar, nroPoblacion, posActual, individuoAMigrarCPUaGPUhost);
		}
		if(imprimirPoblacionEntera == 0){
			//obtengo el mejor individuo
			int posMejor = obtenerMejorIndividuoEntera(nroPoblacion, nuevoFitness);
			for(int i = 0; i < cantGenesEnCromosoma; i++){
				mejorIndividuo[i + nroPoblacion * cantGenesEnCromosoma] = nuevaPoblacion[posMejor+i];
			}
			//asignar mejor fitness
			mejorFitnessIndividuoCPU[nroPoblacion] = nuevoFitness[posMejor/cantGenesEnCromosoma];
		}
	}
}

 void obtenerMejoresIndividuosEnteraCPU(int* poblacion, float* fitness, int* mejorIndividuo, float* mejorFitnessIndividuoCPU){
 	//obtengo el mejor individuo
	for(int nroPoblacion = 0; nroPoblacion < cantidadPoblacionesCPU; nroPoblacion++){
		int posMejor = obtenerMejorIndividuoEntera(nroPoblacion, fitness);
		for(int i = 0; i < cantGenesEnCromosoma; i++){
			mejorIndividuo[nroPoblacion * cantGenesEnCromosoma + i] = poblacion[posMejor+i];
		}
		//asignar mejor fitness
		mejorFitnessIndividuoCPU[nroPoblacion] = fitness[posMejor/cantGenesEnCromosoma];
	}
 }
 
 /******************* Implementacion de Funciones de Migracion *****************/

  //Obtiene el mejor individuo de una poblacion (1 bloque por poblacion)
  //selecciona el mejor elemento
 int obtenerMejorIndividuoEntera(int nroPoblacion, float* vectorFitness){
	float mejor = INT_MIN;
  	int indiceMejor;
  	float valorFitness;
  	int indiceMemoria = nroPoblacion * cantCromosomasPoblacion;
  	for(int i = 0; i < cantCromosomasPoblacion; i++){
  		valorFitness = vectorFitness[indiceMemoria+i];
  		if(valorFitness > mejor){
  			mejor = valorFitness;
  			indiceMejor = i;
  		}
  	}
  	int posicionCromosomaMejor = nroPoblacion * cantCromosomasPoblacion* cantGenesEnCromosoma+ indiceMejor * cantGenesEnCromosoma;
  	return posicionCromosomaMejor;
  }

  //Obtiene el indice del peor individuo y del fitness del peor individuo de una poblacion (1 bloque por poblacion) y retorna por referencia en el arreglo indices
  void obtenerPeorIndividuoEntera(int nroPoblacion,float* vectorFitness, int indices[2]){
	float peor = INT_MAX;
  	int indicePeor;
  	float valorFitness;
  	int posicionCromosomaPeor;
  	int indiceMemoria = nroPoblacion * cantCromosomasPoblacion;
  	for(int i = 0; i< cantCromosomasPoblacion; i++){
  		valorFitness = vectorFitness[indiceMemoria+i];
  		if(valorFitness < peor){
  			peor = valorFitness;
  			indicePeor = i;
  		}
  	}
  	posicionCromosomaPeor = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + indicePeor * cantGenesEnCromosoma;
  	indices[0] = posicionCromosomaPeor;
  	indices[1] = indicePeor;
  }

  void migracionRepresentacionEnteraCPU(int* poblacionActual, float* fitnessActual, int* individuosAMigrar, MersenneTwister *mt, int* individuoAMigrarGPUaCPUhost){
 	int indices[2];
 	int posicionCromosomaEmigrante;
 	int posicionCromosomaInmigrante;
 	int posicionFitness;
 	int aux;
 	for(int bloq = 0; bloq < cantidadPoblacionesCPU; bloq++){
 		if(bloq == 0){
			aux = cantidadPoblacionesCPU - 1;
		}else{
			aux = (bloq - 1) % cantidadPoblacionesCPU;
		}
		posicionCromosomaInmigrante = aux * cantGenesEnCromosoma;
 		obtenerPeorIndividuoEntera(bloq, fitnessActual, indices);

 		posicionCromosomaEmigrante = indices[0];
 		if(bloq == 0 && cantidadPoblacionesGPU > 0){
 			for(int i = 0; i<cantGenesEnCromosoma; i++){
 				poblacionActual[posicionCromosomaEmigrante+i] = individuoAMigrarGPUaCPUhost[i];
 			}
 		}else{
 			for(int i = 0; i<cantGenesEnCromosoma; i++){
 				poblacionActual[posicionCromosomaEmigrante+i] = individuosAMigrar[posicionCromosomaInmigrante+i];
 			}
 		}
 		posicionFitness = bloq * cantCromosomasPoblacion + indices[1];
 		fitnessActual[posicionFitness] = calcularFitnessEnteraCPU(poblacionActual, posicionCromosomaEmigrante);
 		printf("++++++++++++++++++++++++++ CPU ++++++++++++++++++++++++++++++++\n");
 		printf("posicionFitness = %d \n", posicionFitness);
 		printf("posicionCromosomaEmigrante = %d \n", posicionCromosomaEmigrante);
 		printf("posicionCromosomaInmigrante = %d \n", posicionCromosomaInmigrante);
 	}
 }

void individuosAMigrarRepresentacionEnteraCPU(float* nuevoFitness, int* nuevaPoblacion, int* individuosAMigrar, int nroPoblacion, int posActual, int *individuoAMigrarCPUaGPUhost){
 	int posicionMejorIndividuo = obtenerMejorIndividuoEntera(nroPoblacion, nuevoFitness);
 	cout <<"////////////////////nroPoblacion -> " <<nroPoblacion <<"\n";
 	if(cantidadPoblacionesGPU > 0 && nroPoblacion == cantidadPoblacionesCPU-1){
 		cout <<"/////////// entra acá ////////////\n";
 		for(int i = 0; i<cantGenesEnCromosoma; i++){
 			individuoAMigrarCPUaGPUhost[i] = nuevaPoblacion[posicionMejorIndividuo+i];
 		}
 	}else{
 		for(int i = 0; i<cantGenesEnCromosoma; i++){
 			individuosAMigrar[nroPoblacion*cantGenesEnCromosoma + i] = nuevaPoblacion[posicionMejorIndividuo+i];
 		}
 	}
 }


/******************* Implementacion de Funciones de Selecccion *****************/

void asignarProbabilidadRuletaEnteraCPU(float* fitnessActual, float* probabilidadRuletaEntera, float* fitnessTotalParaRuleta,  MersenneTwister *mt, int nroPoblacion, int posActual){
	printf("*****asignarProbabilidadRuletaEnteraCPU******\n");
	//printf("posActual = %d\n",posActual);
	printf("cantCromosomasPoblacion/2 - 1 = %d\n", cantCromosomasPoblacion/2 - 1);
	if(posActual == 0){
		fitnessTotalParaRuleta[nroPoblacion] = 0;
		for(int i = nroPoblacion*cantCromosomasPoblacion; i < nroPoblacion*cantCromosomasPoblacion + cantCromosomasPoblacion; i++){
			fitnessTotalParaRuleta[nroPoblacion] += fitnessActual[i];
		}

		for(int i = nroPoblacion*cantCromosomasPoblacion; i < nroPoblacion*cantCromosomasPoblacion + cantCromosomasPoblacion; i++){
			probabilidadRuletaEntera[i] = fitnessActual[i]/fitnessTotalParaRuleta[nroPoblacion] * 100;
		}
	}
}

 int seleccionEnteraCPU(float* vectorFitness, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual, float* probabilidadRuleta, int* vectorIndicesFitnessOrdenado, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo){
	int resultado = -1;
	if(ejecutarFuncion == 0){
		resultado = seleccionPorRangoEnteraCPU(vectorIndicesFitnessOrdenado, mt, nroPoblacion, posActual, numerosAleatoriosSeleccion, nroIndividuo);
	}else{
		if(ejecutarFuncion == 1){
			resultado = seleccionPorTorneoEnteraCPU(vectorFitness, mt, nroPoblacion, posActual,  numerosAleatoriosSeleccion, nroIndividuo);
		}else{
			if(ejecutarFuncion == 2){
				resultado = seleccionRuedaRuletaEnteraCPU(probabilidadRuleta, mt, nroPoblacion, posActual, numerosAleatoriosSeleccion, nroIndividuo);
			}
		}
	}
	return resultado;
}


//Seleccion por torneo
//selecciona 2 individuos al azar y devuelve la posicion del mejor
 int seleccionPorTorneoEnteraCPU(float* vectorFitness, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo){
	//printf("*** Seleccion por torneo ***\n");
	int indice = nroPoblacion * cantCromosomasPoblacion * 2 + posActual * 4 + nroIndividuo * 2;
	//printf("i0 = %d, valor = %10.8lu\n", indice, numerosAleatoriosSeleccion[indice]);
	unsigned int r = numerosAleatoriosSeleccion[indice] % cantCromosomasPoblacion;
	int posicionFitnessAleatoria1 = nroPoblacion * cantCromosomasPoblacion + r;
	int posicionCromosomaAleatoria1 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + r * cantGenesEnCromosoma;
	r =  numerosAleatoriosSeleccion[indice+1] % cantCromosomasPoblacion;
	//printf("i1 = %d, valor = %10.8lu\n", indice + 1, numerosAleatoriosSeleccion[indice+1]);
	int posicionFitnessAleatoria2 = nroPoblacion * cantCromosomasPoblacion + r;
	int posicionCromosomaAleatoria2 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + r * cantGenesEnCromosoma;
	if(vectorFitness[posicionFitnessAleatoria1] > vectorFitness[posicionFitnessAleatoria2])
		return posicionCromosomaAleatoria1;
	return posicionCromosomaAleatoria2;
}

 //Seleccion por rango
  int seleccionPorRangoEnteraCPU(int* vectorIndicesFitnessOrdenado, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo){
 	//printf("*** Seleccion por rango ***\n");
	int indice = nroPoblacion * cantCromosomasPoblacion + posActual * 2 + nroIndividuo;
	//printf("i = %d, nroIndividuo = %d, valor = %10.8lu\n", indice, nroIndividuo, numerosAleatoriosSeleccion[indice]);
	unsigned int indiceMejor = numerosAleatoriosSeleccion[indice] % cantidadIndividuosSeleccionPorRango;
	//printf("indiceMejor = %d\n", indiceMejor);
 	//printf("vectorIndicesFitnessOrdenado[blockIdx.y * cantCromosomasPoblacion + indiceMejor] = %d\n", vectorIndicesFitnessOrdenado[nroPoblacion * cantCromosomasPoblacion + indiceMejor]);

 	int posicionCromosoma = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + vectorIndicesFitnessOrdenado[nroPoblacion * cantCromosomasPoblacion + indiceMejor] * cantGenesEnCromosoma;
 	return posicionCromosoma;
 }

 //Seleccion por rueda de ruleta
int seleccionRuedaRuletaEnteraCPU(float* probabilidadRuleta, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosSeleccion, int nroIndividuo){
	printf("*** Seleccion por rueda de ruleta ***\n");
	int indice = nroPoblacion * cantCromosomasPoblacion + posActual * 2 + nroIndividuo;
	//printf("posActual = %d, nroPoblacion = %d\n", posActual, nroPoblacion);
	//printf("i = %d, nroIndividuo = %d, valor = %10.8lu\n", indice, nroIndividuo, numerosAleatoriosSeleccion[indice]);
	float aux = numerosAleatoriosSeleccion[indice];
 	float r = fmod(aux, 100);
 	//printf("r, %f\n", r);
 	float suma = probabilidadRuleta[nroPoblacion*cantCromosomasPoblacion];
 	//printf("suma %f\n", suma);
 	int i = 0;
 	while((r > suma) && (i < cantCromosomasPoblacion - 1)){
 		i++;
 		suma = suma + probabilidadRuleta[nroPoblacion * cantCromosomasPoblacion + i];
 	}
 	//printf("i %d\n", i);
	int posicionCromosoma = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + i * cantGenesEnCromosoma;
	return posicionCromosoma;
}

/******************* Implementacion de Funciones de Cruzamiento *****************/

 void cruzamientoRepresentacionEnteraCPU(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento){
	if(ejecutarFuncion == 0){
		cruzamientoCromosoma1Punto(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual, numerosAleatoriosProbabilidadCruzamiento, numerosAleatoriosCruzamiento);
	}else{
		if(ejecutarFuncion == 1){
			cruzamientoCromosoma2Puntos(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual, numerosAleatoriosProbabilidadCruzamiento, numerosAleatoriosCruzamiento);
		}else{
			if(ejecutarFuncion == 2){
				cruzamientoCromosomaUniforme(poblacionActual, nuevaPoblacion, posicionCromosoma1, posicionCromosoma2, probabilidad, mt, nroPoblacion, posActual, numerosAleatoriosProbabilidadCruzamiento);
			}
		}
	}
}

//Se selecciona un punto de corte y se intercambian los genes de los padres para formar los hijos
 void cruzamientoCromosoma1Punto(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento){
	//printf("*** Cruzamiento 1Punto ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	int indice = nroPoblacion * (cantCromosomasPoblacion / 2) + posActual;
	int prob = numerosAleatoriosProbabilidadCruzamiento[indice] % 101;

	if(prob < probabilidad){
		unsigned int r = numerosAleatoriosCruzamiento[indice] % cantGenesEnCromosoma;
		//printf("r %d\n", r);
		for(int i=0; i<cantGenesEnCromosoma; i++){
			if(i < r){
				nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
				nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
			}else{
				nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma2+i];
				nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma1+i];
			}
		}
	}else{
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		}
	}
}

//Se seleccionan 2 puntos de corte y se intercambian los genes de los padres para formar los hijos
 void cruzamientoCromosoma2Puntos(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosCruzamiento){
	//printf("*** Cruzamiento 2Puntos ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	int indiceProb = nroPoblacion * (cantCromosomasPoblacion / 2) + posActual;
	int indiceCruz = nroPoblacion * cantCromosomasPoblacion + posActual * 2;
	//printf("indiceProb = %d, valor = %10.8lu\n", indiceProb, numerosAleatoriosProbabilidadCruzamiento[indiceProb]);
	unsigned int prob = numerosAleatoriosProbabilidadCruzamiento[indiceProb] % 101;
	if(prob < probabilidad){
		unsigned int r1 = numerosAleatoriosCruzamiento[indiceCruz] % cantGenesEnCromosoma;
		unsigned int r2 = numerosAleatoriosCruzamiento[indiceCruz + 1] % cantGenesEnCromosoma;
		//printf("r1 %d, r2 %d\n", r1, r2);
		//printf("r2 %d\n", r2);
		int i = 0;
		while(r2 == r1){
			r2 = (r2 + 1) % cantGenesEnCromosoma;
			i++;
		}
		if(r2<r1){
			unsigned int r3 = r1;
			r1 = r2;
			r2 = r3;
		}
		for(int i=0; i<cantGenesEnCromosoma; i++){
			if(i<r1){
				nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
				nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
			}else if(i<=r2){
				nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma2+i];
				nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma1+i];
			}else{
				nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
				nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
			}
		}
	}else{
		for(int i=0; i<cantGenesEnCromosoma; i++){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		}
	}
}


//en cada posición de los progenitores se decide intercambiar el valor
//genético de cada punto de acuerdo a una probabilidad prefijada
 void cruzamientoCromosomaUniforme(int* poblacionActual, int* nuevaPoblacion, int posicionCromosoma1, int posicionCromosoma2, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadCruzamiento){
	//printf("*** Cruzamiento Uniforme ***\n");
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	unsigned int prob;
	int indice = nroPoblacion * (cantCromosomasPoblacion / 2) * cantGenesEnCromosoma + posActual * cantGenesEnCromosoma;
	for(int i=0; i<cantGenesEnCromosoma; i++){
		prob = (numerosAleatoriosProbabilidadCruzamiento[indice] % 101);
		if(prob < probabilidad ){
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma2+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma1+i];
		//	printf("indice = %d, posicionNuevoGen + i= %d, posicionNuevoGen2 + i = %d,  valor1 = %d,  valor2 = %d\n", indice + i, posicionNuevoCromosoma1 + i, posicionNuevoCromosoma2 + i, nuevaPoblacion[posicionNuevoCromosoma1 + i], nuevaPoblacion[posicionNuevoCromosoma2 + i]);
		}else{
			nuevaPoblacion[posicionNuevoCromosoma1+i] = poblacionActual[posicionCromosoma1+i];
			nuevaPoblacion[posicionNuevoCromosoma2+i] = poblacionActual[posicionCromosoma2+i];
		//	printf("indice = %d, posicionNuevoGen + i= %d, posicionNuevoGen2 + i = %d,  valor1 = %d,  valor2 = %d\n", indice + i, posicionNuevoCromosoma1 + i, posicionNuevoCromosoma2 + i, nuevaPoblacion[posicionNuevoCromosoma1 + i], nuevaPoblacion[posicionNuevoCromosoma2 + i]);
		}
		indice++;
	}
}


/******************* Implementacion de Funciones de Mutacion *****************/

 void mutacionEnteraCPU(int* poblacion, float probabilidad, MersenneTwister *mt, int ejecutarFuncion, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion){
	if(ejecutarFuncion == 0){
		mutacionReajusteAleatorio(poblacion, probabilidad, mt, nroPoblacion, posActual, numerosAleatoriosProbabilidadMutacion, numerosAleatoriosMutacion);
	}else{
		if(ejecutarFuncion == 1){
			mutacionPorDeslizamiento(poblacion, probabilidad, mt, nroPoblacion, posActual, numerosAleatoriosProbabilidadMutacion, numerosAleatoriosMutacion);
		}
	}
}

//Reajuste Aleatorio
//Cambia el valor de cada gen por otro valor posible, el nuevo valor se obtiene sorteando aleatoriamente
//entre todos los valores posibles.
 void mutacionReajusteAleatorio(int* poblacion, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion){
	//printf("*** Mutacion por reajuste aleatorio ***\n");
	unsigned int prob;
	unsigned int r;
	int posicionNuevoCromosoma1 = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	int indiceProb = nroPoblacion * cantCromosomasPoblacion + posActual * 2;
	int indice = nroPoblacion * cantCromosomasPoblacion * 2 + posActual * 4;
	prob = (numerosAleatoriosProbabilidadMutacion[indiceProb] % 101);
	//printf("indice = %d, valor = %10.8lu\n", indice, numerosAleatoriosProbabilidadMutacion[indice]);
	if(prob < probabilidad){
		r = numerosAleatoriosMutacion[indice] % cantGenesEnCromosoma;
		//printf("r  %d\n", r);
		poblacion[posicionNuevoCromosoma1 + r] = obtenerNumeroEnRangoEnteraCPU(numerosAleatoriosMutacion[indice+1]);
	}
	prob = (numerosAleatoriosProbabilidadMutacion[indiceProb + 1] % 101);
	if(prob < probabilidad){
		r = numerosAleatoriosMutacion[indice + 2] % cantGenesEnCromosoma;
		//printf("r  %d\n", r);
		poblacion[posicionNuevoCromosoma2 + r] = obtenerNumeroEnRangoEnteraCPU(numerosAleatoriosMutacion[indice + 3]);
	}
}

//Mutación por Deslizamiento
//Suma un valor que puede ser tanto positivo como negativo al valor de cada gen. Los valores a sumar son
//elegidos aleatoriamente para cada posición.
 void mutacionPorDeslizamiento(int* poblacion, float probabilidad, MersenneTwister *mt, int nroPoblacion, int posActual, unsigned long* numerosAleatoriosProbabilidadMutacion, unsigned long* numerosAleatoriosMutacion){
	//printf("*** Mutacion por deslizamiento ***\n");
	unsigned int prob;
	int posicionNuevoCromosoma1 = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + posActual * cantGenesEnCromosoma * 2;
	int posicionNuevoCromosoma2 = posicionNuevoCromosoma1 + cantGenesEnCromosoma;
	int indice = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + posActual * cantGenesEnCromosoma * 2;
	for(int i=0; i<cantGenesEnCromosoma; i++){
		prob = (numerosAleatoriosProbabilidadMutacion[indice] % 101);
		if(prob < probabilidad ){
			poblacion[posicionNuevoCromosoma1 + i] = obtenerNumeroEnRangoEnteraCPU(poblacion[posicionNuevoCromosoma1 + i] + numerosAleatoriosMutacion[indice]);
		}
		indice++;
	}
	for(int i=0; i<cantGenesEnCromosoma; i++){
		prob = (numerosAleatoriosProbabilidadMutacion[indice] % 101);
		if(prob < probabilidad ){
			poblacion[posicionNuevoCromosoma2 + i] = obtenerNumeroEnRangoEnteraCPU(poblacion[posicionNuevoCromosoma2 + i] + numerosAleatoriosMutacion[indice]);
		}
		indice++;
	}
}

/******************* Implementacion de Funciones de fitness *****************/

 void asignarFitnessEnteraCPU(int* nuevaPoblacion, float* nuevoVectorFitness, int nroPoblacion, int posActual, float* fitnessOrdenado){
	//Obtengo posicion del primer cromosoma.
	int posicionCromosoma = posActual * cantGenesEnCromosoma * 2 + nroPoblacion * totalGenesEnPoblacion;
	int posicionFitness = posActual * 2 + nroPoblacion * cantCromosomasPoblacion;
	nuevoVectorFitness[posicionFitness] = calcularFitnessEnteraCPU(nuevaPoblacion, posicionCromosoma);
	nuevoVectorFitness[posicionFitness + 1] = calcularFitnessEnteraCPU(nuevaPoblacion, posicionCromosoma + cantGenesEnCromosoma);
	fitnessOrdenado[posicionFitness] = nuevoVectorFitness[posicionFitness];
	fitnessOrdenado[posicionFitness + 1] = nuevoVectorFitness[posicionFitness + 1];
}


 /******************** Implementacion de Funciones de reemplazo **************/

void reemplazoEnteraCPU(int * poblacionActual, int * nuevaPoblacion, int * poblacionActualAcambiar, int * nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int ejecutarFuncion, int nroPoblacion, int posActual){
 	if(ejecutarFuncion == 1){
 		reemplazoElitistaEnteraCPU(poblacionActual, nuevaPoblacion, poblacionActualAcambiar, nuevaPoblacionAcambiar, fitnessActual, nuevoFitness, nroPoblacion, posActual);
 	}
 }

void reemplazoElitistaEnteraCPU(int* poblacionActual, int* nuevaPoblacion, int* poblacionActualAcambiar, int* nuevaPoblacionAcambiar, float * fitnessActual, float* nuevoFitness, int nroPoblacion, int posActual){
 	printf("*****reemplazo Elitista Entera CPU******\n");
 	printf("posActual = %d\n",posActual);
 	printf("nroPoblacion + cantCromosomasPoblacion/2 - 1 = %d\n", cantCromosomasPoblacion/2 - 1);
 	if(posActual == cantCromosomasPoblacion/2 - 1){
 		int cantAremplazar = (int) (porcentajeElitismo * cantCromosomasPoblacion / 100);
 		float peor = INT_MAX;
 		float mejor = INT_MIN;
 		int posPeor = -1;
 		int posMejor = -1;
 		int posFitness = nroPoblacion * cantCromosomasPoblacion;
 		for(int i = 0; i < cantAremplazar; i++){
 			if(fitnessActual[posFitness+i] < peor){
 				peor = fitnessActual[posFitness+i];
 				posPeor = i;
 			}
 			if(nuevoFitness[posFitness+i] > mejor){
 				mejor = nuevoFitness[posFitness+i];
 				posMejor = i;
 			}
 			poblacionActualAcambiar[posFitness+i] = 1;
 			nuevaPoblacionAcambiar[posFitness+i] = 1;
 		}
 		printf("peor = %d\n",peor);
 		printf("mejor = %d\n",mejor);
 		for(int i = cantAremplazar; i < cantCromosomasPoblacion; i++){
 			if(fitnessActual[posFitness+i] > peor){
 				poblacionActualAcambiar[posFitness+i] = 1;
 				poblacionActualAcambiar[posFitness+posPeor] = 0;
 				peor = INT_MAX;
 				posPeor = -1;
 				for(int j = 0; j <= i; j++){
 					if(poblacionActualAcambiar[posFitness+j] == 1){
 						if(fitnessActual[posFitness+j] < peor){
 							peor = fitnessActual[posFitness+j];
 							posPeor = j;
 						}
 					}
 				}
 			}else{
 				poblacionActualAcambiar[posFitness+i] = 0;
 			}
 			if(nuevoFitness[posFitness+i] < mejor){
 				nuevaPoblacionAcambiar[posFitness+i] = 1;
 				nuevaPoblacionAcambiar[posFitness + posMejor] = 0;
 				mejor = INT_MIN;
 				posMejor = -1;
 				for(int j = 0; j <= i; j++){
 					if(nuevaPoblacionAcambiar[posFitness+j] == 1){
 						if(nuevoFitness[posFitness+j] > mejor){
 							mejor = nuevoFitness[posFitness+j];
 							posMejor = j;
 						}
 					}
 				}
 			}else{
 				nuevaPoblacionAcambiar[posFitness+i] = 0;
 			}
 		}
 		for(int i = posFitness; i < posFitness + cantCromosomasPoblacion; i++){
			printf("poblacionActualAcambiar[%d] = %d\n",i,poblacionActualAcambiar[i]);
			//cuPrintf("nuevaPoblacionAcambiar[%d] = %d\n",i,nuevaPoblacionAcambiar[i]);
		}
		for(int i = posFitness; i < posFitness + cantCromosomasPoblacion; i++){
			//cuPrintf("poblacionActualAcambiar[%d] = %d\n",i,poblacionActualAcambiar[i]);
			printf("nuevaPoblacionAcambiar[%d] = %d\n",i,nuevaPoblacionAcambiar[i]);
		}
 		for(int i = 0; i < cantAremplazar; i++){
 			int j = 0;
 			while(poblacionActualAcambiar[posFitness+j] == 0){
 				j++;
 			}
 			int k = 0;
 			while(nuevaPoblacionAcambiar[posFitness+k] == 0){
 				k++;
 			}
 			nuevoFitness[posFitness+k] = fitnessActual[posFitness+j];
 			int posNuevoCromosoma = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + k * cantGenesEnCromosoma;
 			int posCromosomaActual = nroPoblacion * cantCromosomasPoblacion * cantGenesEnCromosoma + j * cantGenesEnCromosoma;
 			for(int h = 0; h < cantGenesEnCromosoma; h++){
 				nuevaPoblacion[posNuevoCromosoma+h] = poblacionActual[posCromosomaActual+h];
 			}
 			poblacionActualAcambiar[posFitness+j] = 0;
 			nuevaPoblacionAcambiar[posFitness+k] = 0;
 		}
 	}
 }

/******************* Implementacion de Funciones del host *****************/
 void imprimirEnteraCPU(float* fitnessHost, int tamVectorFitness, int* poblacionHost, int tamVectorPoblacion, int iteracion){
  	cout << "\nPOBLACION ITERACION "<< iteracion<<" CPU\n";
  	for(int i = 0; i<totalGenesCPU; i++){
  		if(i%cantGenesEnCromosoma == 0){
  			cout << "\n";
  		}
  		printf("%i ", poblacionHost[i]);
  	}
  	cout << "\n\n\nFITNESS CPU\n";
  	for(int i = 0; i<cantCromosomasPoblacion * cantidadPoblacionesCPU; i++){
  		printf("%f ", fitnessHost[i]);
  	}
  	cout << "\n\n\n\n";
 }

void imprimirMejorIndividuoEnteraCPU(float* mejorFitnessIndividuoCPU, int tamVectorFitnessMejoresIndividuosCPU, int* mejorIndividuoCPU, int tamVectorMejoresIndividuosCPU, int iteracion){
 	cout << "\nMEJOR INDIVIDUO ITERACION "<< iteracion<<" CPU enteraCPU.cu\n";
 	for(int i = 0; i < cantGenesEnCromosoma * cantidadPoblacionesCPU; i++){
 		if(i%cantGenesEnCromosoma == 0){
			cout << "\n";
		}
 		printf("%i ", mejorIndividuoCPU[i]);
 	}
 	cout << "\n\n\nFITNESS MEJOR INDIVIDUOS CPU\n";
 	for(int i = 0; i < cantidadPoblacionesCPU; i++){
		printf("%f ", mejorFitnessIndividuoCPU[i]);
	}
	cout << "\n\n\n\n";
}


void representacionEnteraCPU(int *poblacionActualHost, int *nuevaPoblacionHost, float *fitnessActualHost, float *nuevoFitnessHost,int * poblacionActualAcambiar, int *  nuevaPoblacionAcambiar, int * individuosAMigrarHostCPU, MersenneTwister* mt, int iteracion, int tamVectorPoblacion, int tamVectorFitness, int *individuoAMigrarCPUaGPUhost, float* fitnessOrdenadoHostCPU, int* indicesFitnessOrdenadoHostCPU, float* probabilidadRuletaHostCPU, float* fitnessTotalParaRuletaHostCPU, unsigned long* numerosAleatoriosSeleccion, unsigned long* numerosAleatoriosCruzamiento, unsigned long* numerosAleatoriosMutacion, unsigned long* numerosAleatoriosProbabilidadCruzamiento, unsigned long* numerosAleatoriosProbabilidadMutacion, float* mejorFitnessIndividuoCPU, int tamVectorFitnessMejoresIndividuosCPU, int* mejorIndividuoCPU, int tamVectorMejoresIndividuosCPU){
	int nroPoblacion = 0;
	for(int i = 0; i < cantidadPoblacionesCPU*cantCromosomasPoblacion/2; i++){
		nroPoblacion = i/(cantCromosomasPoblacion/2);
		if((iteracion % 2) == 0){
			mainKernelEnteraCPU(poblacionActualHost, nuevaPoblacionHost, fitnessActualHost, nuevoFitnessHost, poblacionActualAcambiar, nuevaPoblacionAcambiar, individuosAMigrarHostCPU, mt, nroPoblacion, i%(cantCromosomasPoblacion/2), individuoAMigrarCPUaGPUhost, fitnessOrdenadoHostCPU, indicesFitnessOrdenadoHostCPU, iteracion, probabilidadRuletaHostCPU, fitnessTotalParaRuletaHostCPU, numerosAleatoriosSeleccion, numerosAleatoriosCruzamiento, numerosAleatoriosMutacion, numerosAleatoriosProbabilidadCruzamiento, numerosAleatoriosProbabilidadMutacion, mejorIndividuoCPU, mejorFitnessIndividuoCPU);
		}else{
			mainKernelEnteraCPU(nuevaPoblacionHost, poblacionActualHost, nuevoFitnessHost, fitnessActualHost, poblacionActualAcambiar, nuevaPoblacionAcambiar, individuosAMigrarHostCPU, mt, nroPoblacion, i%(cantCromosomasPoblacion/2), individuoAMigrarCPUaGPUhost, fitnessOrdenadoHostCPU, indicesFitnessOrdenadoHostCPU, iteracion, probabilidadRuletaHostCPU, fitnessTotalParaRuletaHostCPU, numerosAleatoriosSeleccion, numerosAleatoriosCruzamiento, numerosAleatoriosMutacion, numerosAleatoriosProbabilidadCruzamiento, numerosAleatoriosProbabilidadMutacion, mejorIndividuoCPU, mejorFitnessIndividuoCPU);
		}
	}

	//Imprimo solo en la ultima iteracion o si esta en modo debug imprimo siempre
	if((iteracion == numeroGeneraciones - 1) || (modoDebug == 1)){
		if((iteracion % 2) == 0){
			if(imprimirPoblacionEntera == 1)
				imprimirEnteraCPU(nuevoFitnessHost, tamVectorFitness, nuevaPoblacionHost, tamVectorPoblacion, iteracion);
			else
				imprimirMejorIndividuoEnteraCPU(mejorFitnessIndividuoCPU, tamVectorFitnessMejoresIndividuosCPU, mejorIndividuoCPU, tamVectorMejoresIndividuosCPU, iteracion);
		}else{
			if(imprimirPoblacionEntera == 1)
				imprimirEnteraCPU(fitnessActualHost, tamVectorFitness, poblacionActualHost, tamVectorPoblacion, iteracion);
			else
				imprimirMejorIndividuoEnteraCPU(mejorFitnessIndividuoCPU, tamVectorFitnessMejoresIndividuosCPU, mejorIndividuoCPU, tamVectorMejoresIndividuosCPU, iteracion);
		}
	}
}


#endif

